/********************************************************** 
 * ActionScript Development Tool 
 * Copyright (C) 2005 asdt.org 
 *  
 * http://www.asdt.org 
 * http://sourceforge.net/projects/aseclipseplugin/ 
 * 
 * This program is free software;  
 * you can redistribute it and/or modify it under the terms of  
 * the GNU General Public License as published by the  
 * Free Software Foundation; either version 2 of the License,  
 * or (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful,  
 * but WITHOUT ANY WARRANTY; without even the implied warranty of  
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * See the GNU General Public License for more details. 
 *  
 * You should have received a copy of the GNU General Public License  
 * along with this program; if not, write to the  
 * Free Software Foundation, Inc.,  
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.  
 * 
 *  
 **********************************************************/

package ca.scotthyndman.as2haxe.dom;

import java.util.ArrayList;
import java.util.List;

import ca.scotthyndman.as2haxe.dom.visitor.IVisitor;

/**
 * For implicit getter/setter support.
 */
public class ASPropertyDeclaration extends ASBodyDeclaration {

	/**
	 * The "name" structural property of this node type.
	 * 
	 * 
	 */
	public static final ASChildPropertyDescriptor NAME_PROPERTY = new ASChildPropertyDescriptor(
			ASPropertyDeclaration.class, "name", ASSimpleName.class, true);

	/**
	 * The "getter" structural property of this node type.
	 * 
	 * 
	 */
	public static final ASChildPropertyDescriptor GETTER_PROPERTY = new ASChildPropertyDescriptor(
			ASPropertyDeclaration.class, "getter", ASFunction.class, false);

	/**
	 * The "setter" structural property of this node type.
	 * 
	 * 
	 */
	public static final ASChildPropertyDescriptor SETTER_PROPERTY = new ASChildPropertyDescriptor(
			ASPropertyDeclaration.class, "setter", ASFunction.class, false);

	/**
	 * The "type" structural property of this node type
	 * 
	 * 
	 */
	public static final ASChildPropertyDescriptor TYPE_PROPERTY = new ASChildPropertyDescriptor(
			ASPropertyDeclaration.class, "type", ASType.class, true);

	/**
	 * A list of property descriptors (element type:
	 * {@link ASPropertyDescriptor}), or null if uninitialized.
	 */
	private static final List<ASPropertyDescriptor> PROPERTY_DESCRIPTORS;

	static {
		List<Object> properyList = new ArrayList<Object>(5);
		createPropertyList(ASPropertyDeclaration.class, properyList);
		addProperty(NAME_PROPERTY, properyList);
		addProperty(GETTER_PROPERTY, properyList);
		addProperty(SETTER_PROPERTY, properyList);
		addProperty(TYPE_PROPERTY, properyList);
		PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
	}

	/**
	 * Returns a list of structural property descriptors for this node type.
	 * Clients must not modify the result.
	 * 
	 * @return a list of property descriptors (element type:
	 *         {@link ASPropertyDescriptor})
	 */
	public static List<ASPropertyDescriptor> propertyDescriptors() {
		return PROPERTY_DESCRIPTORS;
	}

	//
	// ======== MEMBERS
	//

	private ASSimpleName name;

	private ASFunction getter;

	private ASFunction setter;

	private ASType type;

	//
	// ======== CONSTRUCTION
	//

	public ASPropertyDeclaration(AST ast) {
		super(ast);
	}

	public ASSimpleName getName() {
		return name;
	}

	public void setName(ASSimpleName name) {
		if (name == null) {
			throw new IllegalArgumentException();
		}
		ASTNode oldChild = this.name;
		preReplaceChild(oldChild, name, NAME_PROPERTY);
		this.name = name;
		postReplaceChild(oldChild, name, NAME_PROPERTY);
	}

	public ASFunction getGetter() {
		return getter;
	}

	public void setGetter(ASFunction getter) {
		ASTNode oldChild = this.getter;
		preReplaceChild(oldChild, getter, GETTER_PROPERTY);
		this.getter = getter;
		postReplaceChild(oldChild, getter, GETTER_PROPERTY);
	}

	public ASFunction getSetter() {
		return setter;
	}

	public void setSetter(ASFunction setter) {
		ASTNode oldChild = this.setter;
		preReplaceChild(oldChild, setter, SETTER_PROPERTY);
		this.setter = setter;
		postReplaceChild(oldChild, setter, SETTER_PROPERTY);
	}

	public ASType getType() {
		return type;
	}

	public void setType(ASType type) {
		if (type == null) {
			throw new IllegalArgumentException();
		}
		ASTNode oldChild = this.type;
		preReplaceChild(oldChild, type, TYPE_PROPERTY);
		this.type = type;
		postReplaceChild(oldChild, type, TYPE_PROPERTY);
	}

	//
	// ======== INTERNAL GETTERS / SETTERS
	//

	/*
	 * (omit javadoc for this method) Method declared on ASTNode.
	 */
	final ASTNode internalGetSetChildProperty(
			ASChildPropertyDescriptor property, boolean get, ASTNode child) {
		if (property == NAME_PROPERTY) {
			if (get) {
				return getName();
			} else {
				setName((ASSimpleName) child);
				return null;
			}
		}
		if (property == GETTER_PROPERTY) {
			if (get) {
				return getGetter();
			} else {
				setGetter((ASFunction) child);
				return null;
			}
		}
		if (property == SETTER_PROPERTY) {
			if (get) {
				return getSetter();
			} else {
				setSetter((ASFunction) child);
				return null;
			}
		}
		if (property == TYPE_PROPERTY) {
			if (get) {
				return getType();
			} else {
				setType((ASType) child);
				return null;
			}
		}

		// allow default implementation to flag the error
		return super.internalGetSetChildProperty(property, get, child);
	}

	//
	// ======== OVERRIDES
	//

	/**
	 * @see ca.scotthyndman.as2haxe.dom.visitor.IVisitable#accept(ca.scotthyndman.as2haxe.dom.visitor.IVisitor,
	 *      boolean)
	 */
	public void accept(IVisitor as2Visitor, boolean visitChilds) {
		visitChilds = as2Visitor.visit(this);
		if (visitChilds) {
			if (getter != null)
				getter.accept(as2Visitor, visitChilds);
			if (setter != null)
				setter.accept(as2Visitor, visitChilds);
		}
	}

	public String toString() {
		String stringOutput = null;
		if (name != null) {
			stringOutput = name.toString();
		}
		if (getter != null && getter.getReturnType() != null
				&& getter.getReturnType().getName() != null) {
			stringOutput += " : " + getter.getReturnType().getName().toString();
		}
		return stringOutput;
	}
}
